#include "xen/application.hpp"

namespace Xen {

Application* Application::instance_ = nullptr;

Application::Application() {
    if (instance_) {
        XEN_CORE_ERROR("already have an application");
    } else {
        instance_ = this;
    }

    WindowProps props;
    props.title = "XenEngine";
    props.width = 1024;
    props.height = 720;

    window_ = std::unique_ptr<Window>(Window::Create(props));
    window_->SetEventCallback(BIND_EVENT_FN(Application::OnEvent));

    Physical::Init();

    imgui_layer_ = new ImGuiLayer;
    PushOverlay(imgui_layer_);
}

Application::~Application() {
    Physical::Shutdown();
}

void Application::PushLayer(Layer* layer) {
    layer_stack_.PushLayer(layer);
    layer->OnAttach();
}

void Application::PushOverlay(Layer* layer) {
    layer_stack_.PushOverlay(layer);
    layer->OnAttach();
}

void Application::OnEvent(Event &e) {
    EventDispatcher dispatcher(e);
    dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(Application::onWindowClose));
    dispatcher.Dispatch<WindowResizeEvent>(BIND_EVENT_FN(Application::onWindowResize));

    for (auto it = layer_stack_.end(); it != layer_stack_.begin();) {
        (*--it)->OnEvent(e);
        if (e.IsHandled()) {
            break;
        }
    }
}

bool Application::onWindowResize(WindowResizeEvent &event) {
    if (event.GetSize().w == 0 || event.GetSize().h == 0) {
        is_minimized_ = true;
        return false;
    }
    is_minimized_ = false;
    Renderer::OnWindowResize(event.GetSize().w, event.GetSize().h);
    return false;
}

bool Application::onWindowClose(WindowCloseEvent&e) {
    Exit();
    return true;
}

void Application::Run() {
    while (IsRunning()) {
        float t = SDL_GetTicks();
        TimeStep ts = t - old_time_;
        old_time_ = t;

        if (!is_minimized_) {
            for (Layer* layer: layer_stack_)
                layer->OnUpdate(ts);
        }

        imgui_layer_->Begin();
        for (Layer* layer: layer_stack_)
            layer->OnImGuiRender();
        imgui_layer_->End();

        window_->OnUpdate();
    }
}

}
